package com.demo.testversion1

import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.junit.Test
import java.io.IOException

/**
 * Created by zhangyuncai on 2025/1/21.
 * 描述：
 */
class CoroutineTest05 {
    @Test
    fun `test CoroutineContext`(): Unit = runBlocking {
        launch(Dispatchers.Default + CoroutineName("test")) {//+ 是因为内部有plus重载
            println("working thread:${Thread.currentThread().name}")
        }
    }

    @Test
    fun `test CoroutineContext extend`(): Unit = runBlocking {
        val scope = CoroutineScope(Job() + Dispatchers.IO + CoroutineName("test"))
        val job = scope.launch {
            println("${coroutineContext[Job]}  thread.name${Thread.currentThread().name}")
            val result = async {
                println("${coroutineContext[Job]}  thread.name${Thread.currentThread().name}")
                "OK"
            }.await()
        }
        job.join()
    }

    @Test
    fun `test CoroutineContext extend2`(): Unit = runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->//_表示不会赋值
            println("exception:${throwable}")
        }
        val scope = CoroutineScope(Job() + Dispatchers.Main + coroutineExceptionHandler)
        val job = scope.launch(Dispatchers.IO) {

        }
    }

    @Test
    fun `test CoroutineContext propagation`(): Unit = runBlocking {
        val job = GlobalScope.launch {
            try {
                throw IndexOutOfBoundsException()
            } catch (e: Exception) {
                println("exception:${e}")
            }

        }
        job.join()
        val deferred = GlobalScope.async {
            throw ArithmeticException()
        }
        try {
            deferred.await()
        } catch (e: Exception) {
            println("exception:${e}")
        }


    }

    @Test
    fun `test CoroutineContext propagation2`(): Unit = runBlocking {
        val scope = CoroutineScope(Job())
        val job = scope.launch {
            async {//产生的协程会被传播
                throw IllegalStateException()
            }
        }
        job.join()

    }

    @Test
    fun `test SupervisorJob`(): Unit = runBlocking {
//        val supervisor = CoroutineScope(SupervisorJob())//SupervisorJob会让子线程自己处理异常
        val supervisor = CoroutineScope(Job())
        val job1 = supervisor.launch {
            delay(100)
            println("child 1")
            throw IllegalStateException()
        }
        val job2 = supervisor.launch {
            try {
                delay(Long.MAX_VALUE)
            } finally {
                println("job2 finished")
            }
        }
//        supervisor.cancel()//可以取消内部所有协程
        joinAll(job1, job2)

    }

    @Test
    fun `test supervisorScope`(): Unit = runBlocking {
        supervisorScope {
            launch {
                delay(100L)
                println("child 1")
                throw IllegalStateException()
            }
            try {//其他子协程出错,这里不会被取消
                delay(Long.MAX_VALUE)
            } finally {
                println("job2 finished")
            }
        }

    }

    @Test
    fun `test supervisorScope2`(): Unit = runBlocking {
        supervisorScope {
            val child = launch {
                try {
                    println("sleepling")
                    delay(Long.MAX_VALUE)
                } finally {
                    println("cancelld")
                }
            }
            yield()
            println("the scope")
            throw IllegalStateException()//自身失败,会取消所有子协程
        }

    }

    @Test
    fun `test CoroutineExceptionHandler`(): Unit = runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("exception:${throwable}")
        }
        val job = GlobalScope.launch {
            throw AssertionError()
        }
        val deprecated = GlobalScope.async(coroutineExceptionHandler) {
            throw ArithmeticException()
        }
        job.join()
        deprecated.await()
    }

    @Test
    fun `test CoroutineExceptionHandler2`(): Unit = runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("exception:${throwable}")
        }
        val scope = CoroutineScope(Job())
//        val job=scope.launch(coroutineExceptionHandler) {
//            launch {//可以被捕获
//                throw  IllegalStateException()
//            }
//        }
        val job = scope.launch() {
            launch(coroutineExceptionHandler) {//不可以被捕获
                throw IllegalStateException()
            }
        }
        job.join()
    }

    @Test
    fun `test cancel and exception`(): Unit = runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("exception:${throwable}")
        }
        val job = launch {
            val child = launch {
                try {
                    delay(Long.MAX_VALUE)
                } finally {
                    println("cancelld")
                }
            }
            yield()
            println("cancelled child")
            child.cancelAndJoin()//静默处理异常
            yield()
            println("parent not cancelled")
        }
        job.join()
    }

    @Test
    fun `test cancel and exception2`(): Unit = runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("exception:${throwable}")
        }
        val job = GlobalScope.launch(coroutineExceptionHandler) {//如果一个协程遇到了CancellationException以外的异常,它将使用该异常取消它的父协程.
            //当父协程的所有子协程都结束后,异常才会被父协程处理
            launch {
                try {
                    delay(Long.MAX_VALUE)
                } finally {
                    withContext(NonCancellable) {
                        println("NonCancellable")
                        delay(100L)
                        println("NonCancellable2")
                    }
                    println("")
                }
            }

            launch {
                delay(10L)
                println("second exception")
                throw ArithmeticException()
            }
        }
        job.join()
    }

    @Test
    fun `test exception aggregation`(): Unit = runBlocking {
        val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
            println("exception:${throwable.suppressed.contentToString()}")
        }
        val job = GlobalScope.launch(coroutineExceptionHandler) {//如果一个协程遇到了CancellationException以外的异常,它将使用该异常取消它的父协程.
            //当父协程的所有子协程都结束后,异常才会被父协程处理
            launch {
                try {
                    delay(Long.MAX_VALUE)
                } finally {
                    throw ArithmeticException()
                }
            }

            launch {
                delay(100L)
                println("second exception")
                throw IOException()
            }
        }
        job.join()
    }
}